﻿///////////////////////////////////////////////////////////////////////////////
// Copyright 2016 lingzimaike@gmail.com
// GPLv2
// Author: lingzimaike
///////////////////////////////////////////////////////////////////////////////

#ifndef PAPA_UTIL_XML_FILE_H_
#define PAPA_UTIL_XML_FILE_H_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <string>
#include <tinyxml.h>
#include <papa/base.h>

namespace papa {
namespace util {

    class XmlFile
    {
    public:
        typedef TiXmlEncoding   Encoding;
        typedef TiXmlElement    Node;
        typedef TiXmlText       Text;

        const static Encoding kDefaultEncoding = TIXML_DEFAULT_ENCODING;

        XmlFile(void);
        ~XmlFile(void);

        bool Load(const char* file_name, Encoding encoding = kDefaultEncoding);
        static XmlFile* Create(const char* file_name,
            const char* version = "1.0",
            const char* encoding = "utf8",
            const char* standalone = "no");

        bool IsError(void) const;
        const char* GetErrorString(void) const;

        bool Save(void);
        bool Save(const char* file_name);

        Node* CreateRootNode(const char* name);
        Node* CreateNode(const char* name);
        Text* CreateText(const char* value);

        Node* GetRootNode(void);
        const Node* GetRootNode(void) const;

        Node* Find(const char* path);
        Node* FindOrCreate(const char* path);

        const char* GetText(const char* path, const char* default = "");
        int GetInt(const char* path, int default = 0);
        long GetLong(const char* path, long default = 0);
        double GetDouble(const char* path, double default = 0.0f);

        bool SetText(const char* path, const char* value);
        bool SetInt(const char* path, int value);
        bool SetLong(const char* path, long value);
        bool SetDouble(const char* path, double value);

    private:
        mutable TiXmlDocument doc_;
        ::std::string file_name_;

        PAPA_DISALLOW_COPY_AND_ASSIGN(XmlFile)
    };

    inline bool XmlFile::IsError(void) const
    {
        return doc_.Error();
    }
    
    inline const char* XmlFile::GetErrorString(void) const
    {
        return doc_.ErrorDesc();
    }

    inline bool XmlFile::Save(void)
    {
        return doc_.SaveFile(file_name_.c_str());
    }

    inline bool XmlFile::Save(const char* file_name)
    {
        return doc_.SaveFile(file_name);
    }

    inline XmlFile::Node* XmlFile::CreateRootNode(const char* name)
    {
        if (doc_.RootElement() != NULL)
            return NULL;

        Node* node = CreateNode(name);
        if (node != NULL) {
            doc_.LinkEndChild(node);
        }
        return node;
    }

    inline XmlFile::Node* XmlFile::CreateNode(const char* name)
    {
        return new Node(name);
    }

    inline XmlFile::Text* XmlFile::CreateText(const char* value)
    {
        return new Text(value);
    }

    inline XmlFile::Node* XmlFile::GetRootNode(void)
    {
        return doc_.RootElement();
    }

    inline const XmlFile::Node* XmlFile::GetRootNode(void) const
    {
        return doc_.RootElement();
    }

}}  // namespace papa::util

#endif // PAPA_UTIL_XML_FILE_H_
